#pragma once  // 防止头文件被多次包含，确保只被编译一次
#include <string>  // 引入 C++ 标准字符串库
#include <stdarg.h>  // 引入 C 标准库，用于处理可变参数
#include <iostream>  // 引入 C++ 输入输出流库
#include <fstream>  // 引入文件输入输出流库
#include <time.h>  // 引入时间相关的函数
#include <stdio.h>  // 引入 C 标准输入输出函数
#include "LockGuard.hpp"  // 引入自定义的锁保护类（假设这是一个用于线程同步的工具）
#include<unistd.h>
using namespace std;  // 使用标准命名空间

// 全局变量，用于控制是否保存日志到文件
bool gIsSave = false;
const std::string logname = "log.txt";  // 定义日志文件的名称

// 日志级别的枚举，定义了五个不同的日志级别
enum Level
{
    DEBUG = 0,   // 调试级别
    INFO,        // 信息级别
    WARNING,     // 警告级别
    ERROR,       // 错误级别
    FATAL        // 致命错误级别
};

// 保存日志消息到文件的函数
void SaveLogToFile(const string& filename, const string& message)
{
    ofstream _file(filename, ios::app);  // 以追加模式打开文件
    if (!_file.is_open())  // 如果文件打开失败，直接返回
        return;
    _file << message;  // 将消息写入文件，并换行
}

// 将日志级别转换为对应的字符串
string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";  // 返回调试信息
    case INFO:
        return "Info";  // 返回普通信息
    case WARNING:
        return "Warning";  // 返回警告信息
    case ERROR:
        return "Error";  // 返回错误信息
    case FATAL:
        return "Fatal";  // 返回致命错误信息
    default:
        return "No-Known";  // 返回未知信息
    }
}

// 获取当前系统时间并返回格式化的时间字符串
string GetTimeString()
{
    struct tm* formattime;
    time_t curtimes = time(nullptr);  // 获取当前时间戳
    formattime = localtime(&curtimes);  // 将时间戳转换为本地时间
    if (formattime == nullptr)  // 如果时间获取失败，返回空字符串
        return nullptr;
    string res;
    // 格式化当前时间为 "年-月-日 时:分:秒" 的格式
    res = to_string(formattime->tm_year + 1900) + "-" + to_string(formattime->tm_mon + 1) + "-" + to_string(formattime->tm_mday) +
          " " + to_string(formattime->tm_hour) + ":" + to_string(formattime->tm_min) + ":" + to_string(formattime->tm_sec);
    return res;
}

// 定义互斥锁用于线程同步，确保日志操作时不会发生竞态条件
pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;

// 日志消息记录函数
void LogMessage(string filename, int line, int IsSave, int level, const char* format, ...)
{
    string Level = LevelToString(level);  // 获取日志级别的字符串表示
    pid_t self_id = getpid();
    string time_str = GetTimeString();

    va_list va;
    va_start(va, format);  // 获取可变参数列表
    char buffer[1024];
    vsnprintf(buffer, sizeof(buffer), format, va);  // 格式化日志消息
    va_end(va);  // 结束可变参数的处理
    
    string messages = "["+time_str+"]"+
                       "["+Level+"]" +
                       "["+to_string(self_id)+"]"+
                       "["+filename+"]"+"["+to_string(line)+"]"+buffer+"\n";
    LockGurad gurad(_mutex);  // 使用锁保护日志输出，避免多线程冲突
    if (IsSave)  // 如果配置为保存到文件
    {
        SaveLogToFile(logname, messages);  // 将日志保存到文件
    }
    else  // 如果配置为输出到控制台
    {
        cout << messages;  // 输出日志到控制台
    }
}

// 宏定义：用于在代码中简单地记录日志，带有日志级别和格式化参数
#define LOG(level, format, ...) \
do                               \
{                                \
    LogMessage(__FILE__, __LINE__, gIsSave, level, format,##__VA_ARGS__);  \
} while (0)

// 宏定义：启用将日志保存到文件
#define ENABLEFILE() \
do                          \
{                           \
    gIsSave = true;         \
} while (0)

// 宏定义：启用将日志输出到控制台
#define ENABLESCREEN()  \
do                      \
{                       \
    gIsSave = false;    \
} while (0)
